package com.splic.api.controller.product;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.splic.api.service.LoginService;
import com.splic.common.config.QQConfig;
import com.splic.common.core.DeviceContext;
import com.splic.common.core.domain.ResponseObj;
import com.splic.common.core.redis.RedisCache;
import com.splic.common.enums.ThirdUserTypeEnum;
import com.splic.common.exception.BusinessException;
import com.splic.common.utils.RandomCodeUtil;
import com.splic.common.utils.StringUtils;
import com.splic.product.domain.Product;
import com.splic.product.domain.User;
import com.splic.product.domain.UserThirdBind;
import com.splic.product.dto.ThirdLoginDto;
import com.splic.product.service.ProductService;
import com.splic.product.service.ProductUserService;
import com.splic.product.service.ThirdLoginService;
import com.splic.product.service.UserThirdBindService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/apiThirdLogin")
@Slf4j
public class ApiThirdLoginController {


    @Autowired
    private ThirdLoginService thirdLoginServiceImpl;

    @Autowired
    private UserThirdBindService userThirdBindService;

    @Autowired
    private LoginService loginService;

    @Autowired
    private ProductService productServiceImpl;

    @Autowired
    private RedisCache redisCache;
    @Autowired
    private ProductUserService productUserService;

    /**
     * 支付宝和微信快速登录
     * @param thirdType   @see ThirdUserTypeEnum
     * @return
     */
    @GetMapping("/thirdQuickLogin")
    public ResponseObj<ThirdLoginDto> thirdQuickLogin(String code,String thirdType, Integer isForce, String thirdUserId
            , @RequestParam(name = "isMerge", defaultValue = "-1", required = false) Integer isMerge){
        if (StringUtils.isBlank(code)) {
            return ResponseObj.ERROR("code不能为空。");
        }
        if (StringUtils.isBlank(thirdType)) {
            return ResponseObj.ERROR("三方登录类型不能为空。");
        }
        try {
            User user = thirdLoginServiceImpl.thirdQuickLogin(code,thirdType, thirdUserId, isMerge);
            ThirdLoginDto dto = new ThirdLoginDto();
            dto.setThirdUserType(user.getThirdUserType());
            dto.setBindAccount(StringUtils.isNotEmpty(user.getAccount()));
            dto.setThirdUserId(user.getThirdUserId());
            dto.setUserIdentify(user.getUserIdentify());
            dto.setUserId(user.getId());
            dto.setOtherAli(user.getOtherAli());
            if(user.getId() != null){
                thirdLoginServiceImpl.limitLogin(dto, user, isForce);
            } else {
                redisCache.setCacheObject("expire" + user.getThirdUserId(), 1, 5, TimeUnit.MINUTES);
            }
            productUserService.maybeSave(user);
            return ResponseObj.SUCCESS(dto);
        }catch (BusinessException e){
            log.error("thirdQuickLogin登录失败:{}产品{}版本{}设备{}用户{}",e.getMessage(),DeviceContext.getProductPackageKey(), DeviceContext.getVersion(), DeviceContext.getDeviceIdentify(), thirdType);
            if (e.getCode() == 1001) {
                return ResponseObj.ERROR(e.getMessage(), "1001");
            }
            return ResponseObj.ERROR(e.getMessage());
        }catch (Exception e){
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            e.printStackTrace(new PrintStream(baos));
            String exception = baos.toString();
            log.error("baos:" + exception);
            log.error("thirdQuickLogin登录失败:{}产品{}设备{}用户{}",e.getMessage(),DeviceContext.getProductPackageKey(), DeviceContext.getDeviceIdentify(),thirdType + code);
            return ResponseObj.ERROR("登录失败。");
        }
    }

    /**
     * 跳过绑定直接登录
     * @return
     */
    @GetMapping("/skipBindLogin")
    public ResponseObj<ThirdLoginDto> skipBindLogin(String thirdUserId, String thirdUserType, Integer isForce, String code){
        if (!redisCache.hasKey("expire" + thirdUserId)) {
            return ResponseObj.ERROR("登录超时，请重试。");
        }
        if (StringUtils.isBlank(thirdUserId)) {
            return ResponseObj.ERROR("三方用户ID不能为空。");
        }
        if (StringUtils.isBlank(thirdUserType)) {
            return ResponseObj.ERROR("三方登录类型不能为空。");
        }
        try {
            User user = thirdLoginServiceImpl.skipBindLogin(thirdUserId,thirdUserType,code);
            ThirdLoginDto dto = new ThirdLoginDto();
            dto.setThirdUserType(user.getThirdUserType());
            dto.setBindAccount(StringUtils.isNotEmpty(user.getAccount()));
            dto.setThirdUserId(user.getThirdUserId());
            dto.setUserIdentify(user.getUserIdentify());
            dto.setUserId(user.getId());
            if(user.getId() != null){
                thirdLoginServiceImpl.limitLogin(dto, user, isForce);
            }
            productUserService.maybeSave(user);
            return ResponseObj.SUCCESS(dto);
        }catch (BusinessException e){
            log.error("skipBindLogin登录失败:{}产品{}版本{}设备{}用户{}",e.getMessage(),DeviceContext.getProductPackageKey(), DeviceContext.getVersion(), DeviceContext.getDeviceIdentify(), thirdUserId);
            if (e.getCode() == 1001) {
                return ResponseObj.ERROR(e.getMessage(), "1001");
            }
            return ResponseObj.ERROR(e.getMessage());
        }catch (Exception e){
            log.error("skipBindLogin登录失败:{}产品{}设备{}用户{}",e.getMessage(),DeviceContext.getProductPackageKey(), DeviceContext.getDeviceIdentify(),thirdUserId);
            return ResponseObj.ERROR("登录失败。");
        }
    }

    /**
     * QQ快速登录
     * QQ新版本
     * @param
     * @return
     */
    @GetMapping("/qqQuickLogin")
    public ResponseObj<ThirdLoginDto> qqQuickLogin(String thirdUserId, @RequestParam(required = false, defaultValue = "0") Integer isForce){
        if (StringUtils.isBlank(thirdUserId)) {
            return ResponseObj.ERROR("三方用户ID不能为空。");
        }
        try {
            User user = thirdLoginServiceImpl.checkThirdUserIdIsBindAccount(ThirdUserTypeEnum.qq.name(),thirdUserId);

            ThirdLoginDto dto = new ThirdLoginDto();
            dto.setThirdUserType(user.getThirdUserType());
            dto.setBindAccount(StringUtils.isNotEmpty(user.getAccount()));
            dto.setThirdUserId(user.getThirdUserId());
            dto.setUserIdentify(user.getUserIdentify());
            dto.setUserId(user.getId());
            if(user.getId() != null){
                thirdLoginServiceImpl.limitLogin(dto, user, isForce);
            } else {
                redisCache.setCacheObject("expire" + thirdUserId, 1, 5, TimeUnit.MINUTES);
            }
            productUserService.maybeSave(user);
            return ResponseObj.SUCCESS(dto);
        }catch (BusinessException e){
            log.error("qqQuickLogin登录失败:{}产品{}版本{}设备{}用户{}",e.getMessage(),DeviceContext.getProductPackageKey(), DeviceContext.getVersion(), DeviceContext.getDeviceIdentify(), thirdUserId);
            if (e.getCode() == 1001) {
                return ResponseObj.ERROR(e.getMessage(), "1001");
            }
            return ResponseObj.ERROR(e.getMessage());
        }catch (Exception e){
            log.error("通用qqQuickLogin登录失败:{}产品{}版本{}设备{}用户{}",e.getMessage(),DeviceContext.getProductPackageKey(), DeviceContext.getVersion(), DeviceContext.getDeviceIdentify(), thirdUserId);
            return ResponseObj.ERROR("登录失败。");
        }
    }


    /**
     * 检测三方账号是否绑定账号
     * 兼容QQ和百度账号三方登录方式
     * @param
     * @return
     */
    @GetMapping("/checkIsBindAccount")
    public ResponseObj<ThirdLoginDto> checkIsBindAccount(String thirdType,String thirdUserId, Integer isForce){
        if (StringUtils.isBlank(thirdUserId)) {
            return ResponseObj.ERROR("三方用户ID不能为空。");
        }
        if (StringUtils.isBlank(thirdType)) {
            return ResponseObj.ERROR("三方用户类型不能为空。");
        }
        try {
            User user = thirdLoginServiceImpl.checkThirdUserIdIsBindAccount(thirdType,thirdUserId);

            ThirdLoginDto dto = new ThirdLoginDto();
            dto.setThirdUserType(user.getThirdUserType());
            dto.setBindAccount(StringUtils.isNotEmpty(user.getAccount()));
            dto.setThirdUserId(user.getThirdUserId());
            dto.setUserIdentify(user.getUserIdentify());
            dto.setUserId(user.getId());
            if(user.getId() != null){
                thirdLoginServiceImpl.limitLogin(dto, user, isForce);
            } else {
                redisCache.setCacheObject("expire" + thirdUserId, 1, 5, TimeUnit.MINUTES);
            }
            productUserService.maybeSave(user);
            return ResponseObj.SUCCESS(dto);
        }catch (BusinessException e){
            log.error("checkIsBindAccount登录失败:{}产品{}版本{}设备{}用户{}",e.getMessage(),DeviceContext.getProductPackageKey(), DeviceContext.getVersion(), DeviceContext.getDeviceIdentify(), thirdType + thirdUserId);
            if (e.getCode() == 1001) {
                return ResponseObj.ERROR(e.getMessage(), "1001");
            }
            return ResponseObj.ERROR(e.getMessage());
        }catch (Exception e){
            log.error("checkIsBindAccount登录失败:{}产品{}版本{}设备{}用户{}",e.getMessage(),DeviceContext.getProductPackageKey(), DeviceContext.getVersion(), DeviceContext.getDeviceIdentify(), thirdType + thirdUserId);
            return ResponseObj.ERROR("登录失败。");
        }
    }


    /**
     * 支付宝获取授权请求信息字串
     * @param
     * @return
     */
    @GetMapping("/getAuthInfoStr")
    public ResponseObj<String> getAuthInfoStr(){
        try {
            Product product = productServiceImpl.getByPackageKey(DeviceContext.getProductPackageKey());
            if (product == null){
                return ResponseObj.ERROR("应用获取失败");
            }
            JSONObject jsonObject = JSONObject.parseObject(product.getAlipayConfig());
            if (jsonObject == null){
                return ResponseObj.ERROR("应用支付参数获取失败");
            }
            StringBuilder infoStr=new StringBuilder();
            infoStr.append("apiname=com.alipay.account.auth");
            infoStr.append("&app_id="+ jsonObject.getString("appid"));
            infoStr.append("&app_name=mc");
            infoStr.append("&auth_type=AUTHACCOUNT");
            infoStr.append("&biz_type=openservice");
            infoStr.append("&method=alipay.open.auth.sdk.code.get");
            infoStr.append("&pid="+jsonObject.getString("pid"));//2088开头的合作伙伴id 开发平台中查找
            infoStr.append("&product_id=APP_FAST_LOGIN");
            infoStr.append("&scope=kuaijie");
            infoStr.append("&sign_type=RSA2");
            infoStr.append("&target_id="+RandomCodeUtil.havePrefixCode("TRAGET")); //target_id 随机字符即可 表示每次都是特定的一次请求
            //签名
            String sign = AlipaySignature.rsaSign(infoStr.toString(),jsonObject.getString("private_key"),"UTF-8","RSA2");
            //官方要求URL处理
            infoStr.append("&sign="+ URLEncoder.encode(sign,"UTF-8"));
            return ResponseObj.SUCCESS(infoStr.toString());
        }catch (AlipayApiException e) {
            log.error("获取失败:{}",e.getMessage());
            return ResponseObj.ERROR("获取失败");
        }catch (UnsupportedEncodingException e) {
            log.error("获取失败:{}",e.getMessage());
            return ResponseObj.ERROR("获取失败");
        }catch (BusinessException e){
            log.error("获取失败:{}",e.getMessage());
            return ResponseObj.ERROR(e.getMessage());
        }catch (Exception e){
            log.error("获取失败:{}",e.getMessage());
            return ResponseObj.ERROR("获取失败");
        }
    }

    /**
     * 发起请求
     * @param session
     * @return
     */
    @Deprecated
    @GetMapping("api/qqAuth")
    public String qqAuth(HttpSession session){
        //QQ互联中的回调地址
        String backUrl = QQConfig.REDIRECT_URI + "/apiThirdLogin/api/qqNotify";

        //用于第三方应用防止CSRF攻击
        String uuid = RandomCodeUtil.havePrefixCode("QQ");
        session.setAttribute("state", RandomCodeUtil.havePrefixCode("QQ"));

        //Step1：获取Authorization Code
        String url = "https://graph.qq.com/oauth2.0/authorize?response_type=code"+
                "&client_id=" + QQConfig.APPID +
                "&redirect_uri=" + URLEncoder.encode(backUrl) +
                "&state=" + uuid;
        return "redirect:" + url;
    }


    /**
     * 支付宝快速登录
     * @param
     * @return
     */
    @Deprecated
    @PostMapping("/api/qqNotify")
    public void qqNotify(HttpServletRequest request){
        HttpSession session = request.getSession();

        String code = request.getParameter("code");
        String state = request.getParameter("state");
        String deviceIdentify = (String) session.getAttribute("state");

        thirdLoginServiceImpl.qqNotify(code,deviceIdentify,"", 0);
    }


    /**
     * 快速登录
     * QQ老版本
     * @param
     * @return
     */
    @Deprecated
    @GetMapping("/api/checkQQLogin")
    public ResponseObj<ThirdLoginDto> checkQQLogin(String deviceIdentify, Integer isForce){
        try {
            User user = thirdLoginServiceImpl.checkQQLogin(deviceIdentify);

            ThirdLoginDto dto = new ThirdLoginDto();
            dto.setThirdUserType(user.getThirdUserType());
            dto.setBindAccount(StringUtils.isNotEmpty(user.getAccount()));
            dto.setThirdUserId(user.getThirdUserId());
            dto.setUserIdentify(user.getUserIdentify());
            dto.setUserId(user.getId());
            if(user != null && user.getId() != null && StringUtils.isNotEmpty(user.getAccount())){
                thirdLoginServiceImpl.limitLogin(dto, user, isForce);
            }
            productUserService.maybeSave(user);
            return ResponseObj.SUCCESS(dto);
        }catch (BusinessException e){
            log.error("checkQQLogin登录失败:{}产品{}版本{}设备{}用户{}",e.getMessage(),DeviceContext.getProductPackageKey(), DeviceContext.getVersion(), DeviceContext.getDeviceIdentify(), deviceIdentify);
            if (e.getCode() == 1001) {
                return ResponseObj.ERROR(e.getMessage(), "1001");
            }
            return ResponseObj.ERROR(e.getMessage());
        }catch (Exception e){
            log.error("checkQQLogin登录失败:{}产品{}版本{}设备{}用户{}",e.getMessage(),DeviceContext.getProductPackageKey(), DeviceContext.getVersion(), DeviceContext.getDeviceIdentify(), deviceIdentify);
            return ResponseObj.ERROR("登录失败");
        }

    }


    /**
     * 检测三方绑定
     * @param
     * @return
     */
    @Deprecated
    @GetMapping("/api/checkThirdBind")
    public ResponseObj<Boolean> checkThirdBind(String thirdUserId, String thirdUserType){
        try {
            UserThirdBind userThirdBind = userThirdBindService.getByTypeAndValue(thirdUserType, thirdUserId);
            if(userThirdBind != null){
                log.error("原账号已绑定[QQ/微信/支付宝]登录方式，请问是否更新绑定关系。ThirdUserType:{};ThirdUserId:{}", thirdUserType,thirdUserId);
                return ResponseObj.SUCCESS(true);
            }
            return ResponseObj.SUCCESS(false);
        }catch (BusinessException e){
            log.error("检测三方绑定失败:{}产品{}版本{}设备{}",e.getMessage(),DeviceContext.getProductPackageKey(), DeviceContext.getVersion(), DeviceContext.getDeviceIdentify());
            return ResponseObj.ERROR(e.getMessage());
        }catch (Exception e){
            log.error("检测三方绑定失败:{}产品{}版本{}设备{}",e.getMessage(),DeviceContext.getProductPackageKey(), DeviceContext.getVersion(), DeviceContext.getDeviceIdentify());
            return ResponseObj.ERROR("检测三方绑定失败");
        }

    }

}
